package com.watertek.bdcenter.bdcode.rest;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.zxing.WriterException;
import com.watertek.bdcenter.bdcode.common.Envelop;
import com.watertek.bdcenter.bdcode.common.EnvelopResult;
import com.watertek.bdcenter.bdcode.common.Picture;
import com.watertek.bdcenter.bdcode.common.Range;
import com.watertek.bdcenter.bdcode.entity.User;
import com.watertek.bdcenter.bdcode.util.HttpClientUtil;
import com.watertek.bdcenter.bdcode.util.StringUtil;
import com.watertek.bdcenter.bdcode.vo.ResultPojo;
import com.watertek.geosot.GCode1D;
import com.watertek.geosot.GeoRange;
import com.watertek.geosot.GeoSOT;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;

/**
 * 网格的REST接口类
 */
@RestController
@RequestMapping(value="/geoSOT-API")
public class GridController extends AbstractController {

    /**
     * 该方法是注册用户的方法，默认放开访问控制
     * @param user
     */
    @ResponseBody
    @RequestMapping(value="signup", method= RequestMethod.POST)
    public ResponseEntity<ResultPojo> signUp(@RequestBody User user) {
        // 声明返回结果集
        ResultPojo result = new ResultPojo();

        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        userService.insert(user);

        // 结果集设定
        result.setCode(ResultPojo.CODE_SUCCESS);
        result.setResult(ResultPojo.MSG_SUCCESS);
        result.setMessage(ResultPojo.MSG_SUCCESS);

        return new ResponseEntity<ResultPojo>(result, HttpStatus.OK);
    }

    /**
     * 将经纬度转换为北斗网格码
     * @param request
     * @param response
     * @param longitude 经度
     * @param latitude 纬度
     * @param layer 层级
     * @return
     */
    @ResponseBody
    @RequestMapping(value="Point2Code/{longitude}/{latitude}/{layer}", method= RequestMethod.GET)
    public ResponseEntity<ResultPojo> point2Code(HttpServletRequest request, HttpServletResponse response,
                                                 @PathVariable("longitude") String longitude, @PathVariable("latitude") String latitude,
                                                 @PathVariable("layer") String layer){
        // 声明返回结果集
        ResultPojo result = new ResultPojo();

        GCode1D orgGCode1D=GeoSOT.getGCode1DOfPoint(Double.parseDouble(longitude), Double.parseDouble(latitude), Integer.parseInt(layer));
        BigInteger code=orgGCode1D.getCode();

        // 结果集设定
        result.setCode(ResultPojo.CODE_SUCCESS);
        result.setResult(JSON.toJSONString(code));
        result.setMessage(ResultPojo.MSG_SUCCESS);

        return new ResponseEntity<ResultPojo>(result, HttpStatus.OK);
    }

    /**
     * 根据北斗网格码获取矩形
     * @param request
     * @param response
     * @param code 北斗网格码
     * @return
     */
    @ResponseBody
    @RequestMapping(value="Code2Range/{code}", method= RequestMethod.GET)
    public ResponseEntity<ResultPojo> code2Range(HttpServletRequest request, HttpServletResponse response,
                                               @PathVariable("code") String code){
        // 声明返回结果集
        ResultPojo result = new ResultPojo();

        GCode1D gCode1D=GeoSOT.toGCode1DFromGCode(new BigInteger(code));
        GeoRange geoRange=GeoSOT.toGeoRangeFromGCode1D(gCode1D);
        Range range=new Range();
        range.setMinLat(geoRange.getMinLat());
        range.setMaxLat(geoRange.getMaxLat());
        range.setMinLon(geoRange.getMinLon());
        range.setMaxLon(geoRange.getMaxLon());

        // 结果集设定
        result.setCode(ResultPojo.CODE_SUCCESS);
        result.setResult(JSON.toJSONString(range));
        result.setMessage(ResultPojo.MSG_SUCCESS);

        return new ResponseEntity<ResultPojo>(result, HttpStatus.OK);
    }

    /**
     * 北斗网格码转二维码
     * @param request
     * @param response
     * @param code 北斗网格码
     * @throws IOException
     * @throws WriterException
     */
    @ResponseBody
    @RequestMapping(value="Code2QRCode/{code}", method= RequestMethod.GET)
    public void code2QRCode(HttpServletRequest request, HttpServletResponse response,
                                                  @PathVariable("code") String code) throws IOException, WriterException {
        zxingService.createQrCode(code);
        BufferedImage image = ImageIO.read(new File(Picture.path, Picture.PICTURE_NAME));
        OutputStream out = response.getOutputStream();
        ImageIO.write(image, "png", out);
        out.flush();
    }

    /**
     * 找出这个大的网格内部的所有小的网格，包括这些网格左上角的经纬度，右下角的经纬度和北斗网格码。
     * 当经度向右偏移时，当第一次超出右下角的经度后就换行查找下一行的小网格。纬度向下偏移也是这么做。
     * @param request
     * @param response
     * @param x1 左上角的经度
     * @param y1 左上角的纬度
     * @param x2 右下角的经度
     * @param y2 右下角的纬度
     * @param level 层级
     * @return 返回JSON字符串，具体格式参考/resources/interface-sample.json文件的格式。
     */
    @ResponseBody
    @RequestMapping(value="Range2Envelops/{x1}/{y1}/{x2}/{y2}/{level}", method= RequestMethod.GET)
    public ResponseEntity<ResultPojo> envelops(HttpServletRequest request, HttpServletResponse response,
                           @PathVariable("x1") String x1, @PathVariable("y1") String y1,
                           @PathVariable("x2") String x2, @PathVariable("y2") String y2,
                           @PathVariable("level") String level){
        // 声明返回结果集
        ResultPojo result = new ResultPojo();

        Envelop envelop;
        EnvelopResult envelopResult=new EnvelopResult();

        double p1x=Double.parseDouble(x1);
        double p1y=Double.parseDouble(y1);
        double p2x=Double.parseDouble(x2);
        double p2y=Double.parseDouble(y2);
        int layer=Integer.parseInt(level);

        while (p1y>p2y){
            while(p1x<p2x){
                envelop=this.calculateEnvelop(p1x, p1y, layer);
                envelopResult.getEnvelops().add(envelop);
                p1x+=RIGHTWARD_SHIFT;
            }
            p1y+=DOWNWARD_SHIFT;
        }

        // 结果集设定
        result.setCode(ResultPojo.CODE_SUCCESS);
        result.setResult(JSON.toJSONString(envelopResult));
        result.setMessage(ResultPojo.MSG_SUCCESS);

        return new ResponseEntity<ResultPojo>(result, HttpStatus.OK);
    }

    /**
     * 根绝参数，计算小网格的数据，包括其左上角的经纬度，右下角的经纬度和北斗网格码。
     * @param p1x 左上角的经度
     * @param p1y 左上角的纬度
     * @param layer 层级
     * @return 小网格对象Envelop
     */
    private Envelop calculateEnvelop(double p1x, double p1y, int layer){
        GCode1D orgGCode1D=GeoSOT.getGCode1DOfPoint(p1x, p1y, layer);
        GCode1D newGCode1D = GeoSOT.displaceGCode1D(orgGCode1D, RIGHTWARD_SHIFT, DOWNWARD_SHIFT);

        Range range=new Range();
        range.setMaxLon(p1x+Double.parseDouble(Integer.toString(RIGHTWARD_SHIFT)));
        range.setMinLon(p1x);
        range.setMaxLat(p1y);
        range.setMinLat(p1y+DOWNWARD_SHIFT);

        Envelop envelop=new Envelop();
        envelop.setCode(newGCode1D.getCode().toString());
        envelop.setRange(range);

//        System.out.println(orgGCode1D.getCode());
//        System.out.println(orgGCode1D.getLayer());
//        System.out.println(newGCode1D.getCode());
//        System.out.println(newGCode1D.getLayer());

        return envelop;
    }

    /**
     * 验证北斗码
     * @param request
     * @param response
     * @param code 北斗网格码
     * @return
     */
    @ResponseBody
    @RequestMapping(value="VerifyCode/{code}", method= RequestMethod.GET)
    public ResponseEntity<ResultPojo> verifyCode(HttpServletRequest request, HttpServletResponse response,
                                                 @PathVariable("code") String code){
        // 声明返回结果集
        ResultPojo result = new ResultPojo();

        GCode1D gCode1D=GeoSOT.toGCode1DFromGCode(new BigInteger(code));
        boolean b=GeoSOT.isGCode1DExistent(gCode1D);

        // 结果集设定
        if(b){
            result.setCode(ResultPojo.CODE_SUCCESS);
            result.setMessage(ResultPojo.MSG_SUCCESS);
        }else {
            result.setCode(ResultPojo.CODE_FAILURE);
            result.setMessage("北斗码验证失败！");
        }

        return new ResponseEntity<ResultPojo>(result, HttpStatus.OK);
    }

    /**
     * 根据北斗网格码和十六进制的URL生成二维码
     * @param request
     * @param response
     * @param code 北斗网格码
     * @param url 十六进制的URL
     * @throws IOException
     * @throws WriterException
     */
    @ResponseBody
    @RequestMapping(value="CodeLocation/{code}/{url}", method= RequestMethod.GET)
    public void codeLocation(HttpServletRequest request, HttpServletResponse response,
                             @PathVariable("code") String code, @PathVariable("url") String url) throws IOException, WriterException {
        // 现将16进制的字符串转换为普通字符串（url）,再将北斗网格码追加到这个url后面
        String newUrl=StringUtil.hexStr2Str(url);
        String address=newUrl+"?code="+code;

        zxingService.createQrCode(address);
        BufferedImage image = ImageIO.read(new File(Picture.path, Picture.PICTURE_NAME));
        OutputStream out = response.getOutputStream();
        ImageIO.write(image, "png", out);
        out.flush();
    }

    /**
     * 首先根据地址和城市，调用高德的API，获取经纬度。再根据经纬度和层级，计算北斗网格码
     * @param request
     * @param response
     * @param address
     * @param city
     * @param level
     * @return
     */
    @ResponseBody
    @RequestMapping(value="Address2Code", method= RequestMethod.GET)
    public ResponseEntity<ResultPojo> address2Code(HttpServletRequest request, HttpServletResponse response,
                                                   String address, String city,
                                                   String level){
        // 声明返回结果集
        ResultPojo result = new ResultPojo();

        // 调用高德API，返回json字符串
        String jsonResult=HttpClientUtil.get(AMAP_API_URL, AMAP_API_KEY, address, city);
        JSONObject jsonObject=JSON.parseObject(jsonResult);
        JSONArray jsonArray=JSON.parseArray(jsonObject.get("pois").toString());
        JSONObject jsonObj=JSON.parseObject(jsonArray.get(0).toString());
        String longitude= jsonObj.get("location").toString().split(",")[0];
        String latitude= jsonObj.get("location").toString().split(",")[1];
        String layer=null;
        if(null==level || "".equals(level)){
            layer=new String("18");
        }else{
            layer=level;
        }

        // 计算北斗网格码
        GCode1D orgGCode1D=GeoSOT.getGCode1DOfPoint(Double.parseDouble(longitude), Double.parseDouble(latitude), Integer.parseInt(layer));
        BigInteger code=orgGCode1D.getCode();

        // 结果集设定
        result.setCode(ResultPojo.CODE_SUCCESS);
        result.setResult(code.toString());
        result.setMessage(ResultPojo.MSG_SUCCESS);

        return new ResponseEntity<ResultPojo>(result, HttpStatus.OK);
    }


}
